#pragma once
#ifndef xNet_h__
#define xNet_h__

#include "../inc/xType.h"

namespace Sky
{
	namespace NPlatform
	{

		struct NetAddress {
			i32 type;        ///< Type of address (IPAddress currently)

			/// Acceptable NetAddress types.
			enum {
				IPAddress,
				IPXAddress
			};

			TByte netNum[4];    ///< For IP:  sin_addr<br>
			///  For IPX: sa_netnum

			TByte nodeNum[6];   ///< For IP:  Not used.<br>
			///  For IPX: sa_nodenum (not used by IP)

			TByte  port;       ///< For IP:  sin_port<br>
			///  For IPX: sa_socket
		};

		typedef i32 NetSocket;
		const NetSocket InvalidSocket = -1;

		struct Net
		{
			enum Error
			{
				NoError,
				WrongProtocolType,
				InvalidPacketProtocol,
				WouldBlock,
				NotASocket,
				UnknownError
			};

			enum Protocol
			{
				UDPProtocol,
				IPXProtocol,
				TCPProtocol
			};

			static bool init();
			static void shutdown();

			// Unreliable net functions (UDP)
			// sendto is for sending data
			// all incoming data comes in on packetReceiveEventType
			// App can only open one unreliable port... who needs more? ;)
			static bool  openPort(i32 connectPort);
			static void  closePort();
			static Error sendto(const NetAddress *address, const TByte *buffer, i32 bufferSize);

			// Reliable net functions (TCP)
			// all incoming messages come in on the Connected* events
			static NetSocket openListenPort(TUint16 port);
			static NetSocket openConnectTo(const char *stringAddress); // does the DNS resolve etc.
			static Void     closeConnectTo(NetSocket socket);
			static Error     sendtoSocket(NetSocket socket, const TByte *buffer, i32 bufferSize);

			static void process();

			static bool compareAddresses(const NetAddress *a1, const NetAddress *a2);
			static bool stringToAddress(const char *addressString, NetAddress *address);
			static void addressToString(const NetAddress *address, char addressString[256]);

			// lower level socked based network functions
			static NetSocket openSocket();
			static Error closeSocket(NetSocket socket);

			static Error connect(NetSocket socket, const NetAddress *address);
			static Error listen(NetSocket socket, i32 maxConcurrentListens);
			static NetSocket accept(NetSocket acceptSocket, NetAddress *remoteAddress);

			static Error bind(NetSocket socket, i32    port);
			static Error setBufferSize(NetSocket socket, i32 bufferSize);
			static Error setBroadcast(NetSocket socket, Bool broadcastEnable);
			static Error setBlocking(NetSocket socket, Bool blockingIO);

			static Error send(NetSocket socket, const TByte *buffer, i32 bufferSize);
			static Error recv(NetSocket socket, TByte *buffer, i32 bufferSize, i32 *bytesRead);
		};
	}
}
#endif // xNet_h__
